package nl.Viewer.ViewManager.Views;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;

import javax.swing.JPanel;

import nl.Viewer.Application;
import nl.Viewer.ViewManager.Controllers.GenericController;
import nl.Viewer.ViewManager.Models.DataStoreModelChangeListener;
import nl.Viewer.ViewManager.Models.ParameterModelChangeListener;
import nl.Viewer.ViewManager.Objects.ControllerPair;

/**
 * A generic class for the View component of the Model-View-Controller framework.
 * 
 * @author Jeroen Verschuur
 * 
 */

public abstract class GenericView extends Thread implements DataStoreModelChangeListener, ParameterModelChangeListener,
      MouseListener, MouseMotionListener, MouseWheelListener {
   private static final long         serialVersionUID = -3217307278112938236L;
   protected JPanel                  renderPanel      = null;
   protected final GenericController parent;

   public GenericView( GenericController parent ) {
      this.parent = parent;
   }

   public JPanel getRenderPanel() {
      return renderPanel;
   }

   public void shutdown() {
      // do nothing in default implementation
   }

   public abstract void display();

   public void setPreRenderParameters() { // views can override this function to set parameters just before a render
   }

   protected final void synchronizeViews() {
      // check which views are synchronized with this view
      ArrayList<ControllerPair> pairs = Application.viewManager.getSynchronizableControllers( parent );

      // synchronize all pairs to which we are actually synchronized
      for( int i = 0; i < pairs.size(); i++ ) {
         ControllerPair cp = pairs.get( i );

         if( cp.getObject1().getController() == parent && cp.getObject1().isOtherControllerSynchronized() ) {
            cp.getObject2().getController().synchronizeWith( parent );
         } else if( cp.getObject2().getController() == parent && cp.getObject2().isOtherControllerSynchronized() ) {
            cp.getObject1().getController().synchronizeWith( parent );
         }
      }

   }

   /*
    * Some helper functions used in several views
    */

   /**
    * This method converts an object to a single double value. If the object is not a Double, double, Double, double[1]
    * or Double[1] this method will return null.
    * 
    */
   public static double objectToDouble( Object value ) {
      if( value == null )
         return 0;

      Double v = null;

      if( value instanceof Double[] ) {
         Double[] a = (Double[])value;
         if( a.length == 1 ) {
            v = a[0];
         }
      } else if( value instanceof double[] ) {
         double[] a = (double[])value;
         if( a.length == 1 ) {
            v = a[0];
         }
      } else {

         try {
            v = (Double)value;
         }
         catch( Exception e ) {
            // ignore
         }
      }
      if( v == null ) {
         System.err.println( "Warning: objectToDouble did not recognize value of type " + value.getClass() );
         return 0;
      }
      return v.doubleValue();
   }

   /**
    * This method converts an object to a double array. If the object cannot be cast to a double array, null is
    * returned.
    * 
    */

   public static double[] objectToDoubleArray( Object value ) {
      double[] v = null;
      if( value instanceof Object[] ) {
         Object[] o = (Object[])value;
         v = new double[ o.length ];
         for( int i = 0; i < o.length; i++ ) {
            v[i] = (Double)o[i];
         }
      } else if( value instanceof Double ) {
         v = new double[ 1 ];
         v[0] = (Double)value;
      } else if( value instanceof Double[] ) {
         Double[] o = (Double[])value;
         v = new double[ o.length ];
         for( int i = 0; i < o.length; i++ ) {
            v[i] = o[i];
         }
      } else if( value instanceof double[] ) {
         return( (double[])value );
      }
      if( v == null && value != null ) {
         System.err.println( "Warning: objectToDoubleArray did not recognize value of type " + value.getClass() );
      }
      return v;
   }

   /**
    * This method converts an object to an int array. If the object cannot be cast to an int array, null is returned.
    * 
    */

   public static int[] objectToIntArray( Object value ) {
      int[] v = null;
      if( value instanceof Object[] ) {
         Object[] o = (Object[])value;
         v = new int[ o.length ];
         for( int i = 0; i < o.length; i++ ) {
            v[i] = (Integer)o[i];
         }
      } else if( value instanceof Integer ) {
         v = new int[ 1 ];
         v[0] = (Integer)value;
      } else if( value instanceof Integer[] ) {
         Integer[] o = (Integer[])value;
         v = new int[ o.length ];
         for( int i = 0; i < o.length; i++ ) {
            v[i] = o[i];
         }
      } else if( value instanceof int[] ) {
         return( (int[])value );
      }
      if( v == null ) {
         System.err.println( "Warning: objectToIntArray did not recognize value of type " + value.getClass() );
      }
      return v;
   }

   // Leave all interface implementations below empty, but 'implement' them to prevent views that are extending of the
   // GenericView to implement all methods

   public void mouseReleased( MouseEvent event ) {
   }

   public void mousePressed( MouseEvent event ) {
   }

   public void mouseExited( MouseEvent event ) {
   }

   public void mouseEntered( MouseEvent event ) {
   }

   public void mouseClicked( MouseEvent event ) {
   }

   public void mouseDragged( MouseEvent event ) {
   }

   public void mouseMoved( MouseEvent event ) {
   }

   public void mouseWheelMoved( MouseWheelEvent event ) {
   }

}
